using System.Linq.Expressions;

namespace K3Cloud.WebApi.Core.IoC.Extensions
{
    /// <summary>
    /// 布尔表达式简化规则
    /// 简化布尔运算，如: x && true => x, x || false => x
    /// </summary>
    public class BooleanSimplificationRule : IOptimizationRule
    {
        public string Name => "布尔简化";

        public int Priority => 2;

        public bool CanApply(Expression expression)
        {
            // 检查是否包含可简化的布尔表达式
            var checker = new BooleanSimplificationChecker();
            checker.Visit(expression);
            return checker.HasSimplifiableBoolean;
        }

        public Expression Apply(Expression expression)
        {
            return new BooleanSimplificationVisitor().Visit(expression);
        }

        /// <summary>
        /// 检查是否有可简化的布尔表达式
        /// </summary>
        private class BooleanSimplificationChecker : ExpressionVisitor
        {
            public bool HasSimplifiableBoolean { get; private set; }

            protected override Expression VisitBinary(BinaryExpression node)
            {
                if ((node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse) &&
                    (IsBooleanConstant(node.Left) || IsBooleanConstant(node.Right)))
                {
                    HasSimplifiableBoolean = true;
                }
                return base.VisitBinary(node);
            }

            private static bool IsBooleanConstant(Expression expr)
            {
                return expr is ConstantExpression ce && ce.Type == typeof(bool);
            }
        }

        /// <summary>
        /// 布尔简化访问器
        /// </summary>
        private class BooleanSimplificationVisitor : ExpressionVisitor
        {
            protected override Expression VisitBinary(BinaryExpression node)
            {
                var left = Visit(node.Left);
                var right = Visit(node.Right);

                // x && true => x
                if (node.NodeType == ExpressionType.AndAlso)
                {
                    if (IsTrueConstant(right))
                        return left;
                    if (IsTrueConstant(left))
                        return right;

                    // x && false => false
                    if (IsFalseConstant(right) || IsFalseConstant(left))
                        return Expression.Constant(false);
                }

                // x || false => x
                if (node.NodeType == ExpressionType.OrElse)
                {
                    if (IsFalseConstant(right))
                        return left;
                    if (IsFalseConstant(left))
                        return right;

                    // x || true => true
                    if (IsTrueConstant(right) || IsTrueConstant(left))
                        return Expression.Constant(true);
                }

                // x == true => x
                if (node.NodeType == ExpressionType.Equal)
                {
                    if (IsTrueConstant(right) && left.Type == typeof(bool))
                        return left;
                    if (IsTrueConstant(left) && right.Type == typeof(bool))
                        return right;
                }

                // x == false => !x
                if (node.NodeType == ExpressionType.Equal)
                {
                    if (IsFalseConstant(right) && left.Type == typeof(bool))
                        return Expression.Not(left);
                    if (IsFalseConstant(left) && right.Type == typeof(bool))
                        return Expression.Not(right);
                }

                if (left != node.Left || right != node.Right)
                {
                    return Expression.MakeBinary(node.NodeType, left, right, node.IsLiftedToNull, node.Method);
                }

                return node;
            }

            protected override Expression VisitUnary(UnaryExpression node)
            {
                var operand = Visit(node.Operand);

                // !(true) => false
                // !(false) => true
                if (node.NodeType == ExpressionType.Not && operand is ConstantExpression ce && ce.Type == typeof(bool))
                {
                    return Expression.Constant(!(bool)ce.Value!);
                }

                // !(!x) => x (双重否定)
                if (node.NodeType == ExpressionType.Not && operand is UnaryExpression ue && ue.NodeType == ExpressionType.Not)
                {
                    return ue.Operand;
                }

                if (operand != node.Operand)
                {
                    return Expression.MakeUnary(node.NodeType, operand, node.Type, node.Method);
                }

                return node;
            }

            private static bool IsTrueConstant(Expression expr)
            {
                return expr is ConstantExpression ce && ce.Value is true;
            }

            private static bool IsFalseConstant(Expression expr)
            {
                return expr is ConstantExpression ce && ce.Value is false;
            }
        }
    }
}
